Specification
The specification and other associated documentation explain the project's architecture, design choices, and build process. By convention, this documentation is included in the project’s README file. Whitepapers and docstrings, though helpful for describing particular sections of code, are no replacement for a well-written specification. Without a specification, auditing teams have no way to know what the code should be doing and can’t tell if it works as intended. Hence, the first step of a good audit is ensuring the project contains a full specification, which will serve as the backbone for the audit process.
Code Freeze
Auditors will often ask when a “code freeze” is going to happen, meaning that the code has been finalized. At this step, the code should be in the final draft stage: the developers have looked over everything, ensuring that the best effort has been made at fixing any abnormal or undesirable code. A final commit hash is included in the specification provided to the audit team in order to ensure that both the project team and the audit team agree on the code being audited, and that any changes made to the project are not in scope for the audit.
Testing
Tests are the simplest, easiest way to detect bugs. These range from unit tests targeting individual functions to integration tests addressing larger chunks of code. High test coverage diminishes the number of easily detectable bugs making their way into an audit, making everyone’s lives easier. In addition, tests help to ensure that all developers on a team have agreed upon the project's intended performance and functionalities, preventing confusion during the audit. They also serve as informal documentation for the auditors, demonstrating another way to give the auditors insight into the expected functionality of the project.
The easiest step of an audit is to run the test suite. If all tests pass, then it's less likely there are obvious issues. If tests fail, it's time to see what went wrong and ask the developers whether they knew of failing tests prior to the audit. If a high number of tests fail, it may be necessary to pause the audit before continuing on in case the project team needs to remake massive or critical portions of the codebase.
Automated Analysis
As the demand for safer code grows, so does the development of automated bug detection software. Symbolic execution tools have been developed based on research on common vulnerabilities detected within Solidity smart contracts. These tools analyze a program to determine which inputs cause each part of a program to execute. This software streamlines the auditing process by making it much easier to identify common pitfalls in code, reducing audit turnaround time and freeing up human auditors to focus on complex and novel vulnerabilities.
False Positives
Automated analysis tools for Solidity are in a relatively early stage of development and thus far from perfect. In addition, these tools are not aware of the context in which each piece of code is written. Hence, it is common for these tools to report false positives and incorrectly claim that an issue exists. To ensure that false positives are removed from the report results, manual inspection is required for each reported vulnerability.
Audit Report
After inspection through tests, automated analysis, and manual analysis, the auditing team must compile a report for the project team, ideally accompanied with time for the two teams to discuss and act on the report's findings. This last step is the most essential to seeing through the audit's work into the final project. The project team should fully understand the issues and vulnerabilities detected in the current project, along with the audit team's recommended patches, then integrate those recommendations into the project. If time permits, a follow-up conversation or audit is best practice to ensure no more possible vulnerabilities remain in the project.
A final note is that there is no perfect step-by-step guide to a smart contract audit. Standards are still under development, and different teams follow different design paradigms. In the end, many significant decisions are left to the judgment of the auditing team, and the project team may disagree with the recommendations for reasons that are subjective, cultural, or otherwise. While neither party is necessarily more correct than the other, it takes time to ensure everyone is on the same page about the state of the project. As long as all the information is put forward for open discussion, the likelihood of failure decreases immensely. With all this in mind, communication and scrutiny are clearly critical to the success of a smart contract audit.